package com.kmist.xiakexing.main.socket;

import android.util.Log;

import com.kmist.xiakexing.tools.Config;

import org.json.JSONObject;

import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.xml.transform.sax.TemplatesHandler;

import okio.BufferedSink;
import okio.BufferedSource;
import okio.Okio;

public class SockPresenter implements ISocketPresenter{
    private static boolean lock;
    private static SockPresenter sInstance;
    private List<ISocketCallback> mCallbacks;
    private final ExecutorService executorService;
    private BufferedSink mSink;
    private BufferedSource mSource;

    public static SockPresenter getInstance() {
        if (sInstance == null) {
            synchronized (SockPresenter.class){
                sInstance = new SockPresenter();
            }
        }
        return sInstance;
    }

    public SockPresenter() {
        executorService = Executors.newCachedThreadPool();
        mCallbacks = new ArrayList<>();
    }

    @Override
    public void setCallback(ISocketCallback callback) {
        if (!mCallbacks.contains(callback)) {
            mCallbacks.add(callback);
        }
    }

    @Override
    public void connect() {
        executorService.execute(new connectService());
    }

    @Override
    public void sendMessage(String msg) {
        Log.d("SEND:", msg);
        executorService.execute(new sendService(msg));
    }

    @Override
    public void closeConection() {
        executorService.execute(new sendService("0"));
    }

    @Override
    public void reConection() {

    }


    private class connectService implements Runnable {

        @Override
        public void run() {
            try {
                Socket socket = new Socket(Config.SERVICEADDRESS, Config.SERVICEADDRPORT);
                mSink = Okio.buffer(Okio.sink(socket));
                mSource = Okio.buffer(Okio.source(socket));
                for (ISocketCallback callback : mCallbacks) {
                    callback.onConnected();
                }
                receiveMsg();
            } catch (Exception e) {
                for (ISocketCallback callback : mCallbacks) {
                    callback.onNetworkError();
                }
                e.printStackTrace();
            }
        }

        public void receiveMsg(){
            try {
                while (true){
                    for(String receiveMsg; (receiveMsg = mSource.readUtf8Line()) != null;){
                        final String finalReceiveMsg = receiveMsg;
                        Log.d("RECV", "MSG: "+finalReceiveMsg);
                        //handler
                        lock = false;
                        Log.d("SOCK", "UNLOCK");
                        try{
                            JSONObject jsonObject = new JSONObject(finalReceiveMsg);
                            DataRecver dataRecver = new DataRecver();
                            dataRecver.setResp_code(jsonObject.optInt("resp_code"));
                            dataRecver.setResp_cmd(jsonObject.getString("resp_cmd"));

                            try {
                                String data = jsonObject.getString("resp_data");
                                dataRecver.setResp_data(data);
                            } catch (Exception e) {
                                dataRecver.setResp_data("");
                            }

                            for (ISocketCallback callback : mCallbacks) {
                                callback.onDataRecved(dataRecver);
                            }
                        } catch (Exception e) {
                            for (ISocketCallback callback : mCallbacks) {
                                callback.onNetworkError();
                            }
                            e.printStackTrace();
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private class sendService implements Runnable {
        private String msg;

        sendService(String msg){
            synchronized (SockPresenter.class){
                this.msg = "";
                this.msg = msg;
                this.msg = (msg.length()+1)+this.msg+"\n";
                Log.d("SOCK", "msg ok:"+this.msg);
            }
        }
        @Override
        public void run() {
            synchronized (SockPresenter.class){
                try {
                    Log.d("SOCK", "LOCK");
                    lock = true;
                    mSink.writeUtf8(this.msg);
                    mSink.flush();
                    Log.d("SOCK", "UNLOCK");
                } catch (Exception e) {
                    lock = false;
                    e.printStackTrace();
                }
            }
        }
    }
}
